﻿using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Actor.Net.Network.Gate
{
    public class GateCallContext<TResult> : IGateCallContext
        where TResult : new()
    {
        /// <summary>
        /// 通讯管道
        /// </summary>
        public GateBaseChannel Channel { get; set; }

        /// <summary>
        /// RPC调用Id
        /// </summary>
        public int RpcId { get; set; }

        /// <summary>
        /// RPC同步信号
        /// </summary>
        private TaskCompletionSource<TResult> tcs { get; set; }

        /// <summary>
        /// 处理结果
        /// </summary>
        public TResult result { get; private set; }

        /// <summary>
        /// 设置当前上下文参数
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="rpcId"></param>
        /// <param name="tcs"></param>
        public void SetContext(GateBaseChannel channel, int rpcId, TaskCompletionSource<TResult> tcs)
        {
            this.Channel = channel;
            this.RpcId = rpcId;
            this.tcs = tcs;
            this.result = default;
        }

        /// <summary>
        /// 清空当前上下文参数
        /// </summary>
        public void ClearContext()
        {
            this.Channel = null;
            this.RpcId = 0;
            this.tcs = null;
            this.result = default;
        }

        /// <summary>
        /// 反序列化结果
        /// </summary>
        /// <param name="transferContext"></param>
        public void SetDeserializationResult(GateTransferContext transferContext)
        {
            try
            {
                var type = typeof(TResult);
                if (type == typeof(byte[]))
                {
                    var len = (int)transferContext.ReceiveBodyStream.Length;
                    object bytes = new byte[len];
                    transferContext.ReceiveBodyStream.Read(bytes as byte[], 0, len);
                    result = (TResult)bytes;
                }
                else if (type == typeof(string))
                {
                    var len = (int)transferContext.ReceiveBodyStream.Length;
                    var bytes = new byte[transferContext.ReceiveBodyStream.Length];
                    transferContext.ReceiveBodyStream.Read(bytes, 0, bytes.Length);
                    object str = Encoding.UTF8.GetString(bytes);
                    result = (TResult)str;
                }
                else
                {
                    if (this.Channel.Network.SerializationType == SerializationType.Protobuf)
                    {
                        this.result = (TResult)new MessageParser(() => (IMessage)new TResult()).ParseFrom(transferContext.ReceiveBodyStream);
                    }
                    else if (this.Channel.Network.SerializationType == SerializationType.MessagePack)
                    {
                        this.result = MessagePack.MessagePackSerializer.Deserialize<TResult>(transferContext.ReceiveBodyStream);
                    }
                }
            }
            catch (Exception ex)
            {
                transferContext.ChannelContext.Channel.NetService.ProcessSocketError(transferContext.ChannelContext, ex);
            }
            finally
            {
                tcs?.TrySetResult(result);
            }
        }

        /// <summary>
        /// 设置默认结果
        /// </summary>
        /// <returns></returns>
        public void SetDefaultResult()
        {
            this.result = default;
            tcs?.TrySetResult(result);
        }
    }
}
